home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 May / macformat-024.iso / Shareware City / Developers / TransSkel Pascal 2.5 / TransDisplay / TransDisplay.p < prev    next >
Encoding:
Text File  |  1994-12-14  |  28.1 KB  |  1,096 lines  |  [TEXT/PJMM]

  1. {    TransDisplay version 1.0 - TransSkel plug-in module supporting}
  2. {    an arbitrary number of generic display windows with memory.}
  3.  
  4. {    TransSkel and TransDisplay are public domain, and are written by:}
  5.  
  6. {            Paul DuBois}
  7. {            Wisconsin Regional Primate Research Center}
  8. {            1220 Capital Court}
  9. {            Madison WI  53706  USA}
  10.  
  11. {    UUCP:        [allegra,ihnp4,seismo]!uwvax !uwmacc !dubois }
  12. {    ARPA :     dubois @ unix.macc.wisc.edu }
  13. {                dubois @ rhesus.primate.wisc.edu }
  14.  
  15. {    The Pascal Version of TransSkel is public domain and was ported by        }
  16.  
  17. {            Owen Hartnett            }
  18. {            Ωhm Software            }
  19. {            163 Richard Drive        }
  20. {            Tiverton, RI 02878        }
  21.  
  22. {    CSNET:    omh@cs.brown.edu.CSNET                                             }
  23. {    ARPA:        omh%cs.brown.edu@relay.cs.net-relay.ARPA                        }
  24. {    UUCP:        [ihnp4,allegra]!brunix !omh                                            }
  25.  
  26. {    Psychic Wavelength:  182.2245 Meters  (sorry, couldn't resist)    }
  27.  
  28. {    This version of TransDisplay written for Lightspeed Pascal.  Lightspeed Pascal}
  29. {    is a trademark of:}
  30. {            THINK Technologies, Inc}
  31. {            420 Bedford Street  Suite 350}
  32. {            Lexington, MA  02173  USA}
  33.  
  34.  
  35.  { History}
  36. {  08/25/86    Genesis.  Beta version.}
  37. {  09/15/86    Changed to allow arbitrary number of windows.  Changed}
  38. {             version number to 1.0.}
  39. {  01/10/87    Ported to LightSpeed Pascal by Owen Hartnett                }
  40. {    Ωhm Software, 163 Richard Drive, Tiverton, RI 02878                }
  41. {  12/2/88    Made changes to add conditional compiling if you only need }
  42. {            one TransDisplay window.  Set the following cond variable        }
  43. {            singleDisplay to true if you want only one TransDisplay window }
  44. {            and want smaller code size.    Made adjustments for LSP 2.0    }
  45.  
  46. {dec -94: Two seriou bugs fixed by Ingemar R, both causing problems with multiple TransDisplay windows:}
  47. {– Mouse events could be sent to the wrong display window.}
  48. {– SyncGlobals didn't check dispInfo for nil, which could cause crashes.}
  49.  
  50. unit TransDisplay;
  51.  
  52. interface
  53.  
  54. {$SETC singleDisplay:=false }
  55.     uses
  56. {$IFC UNDEFINED THINK_PASCAL}
  57.         Memtypes, Quickdraw, OSIntf, ToolIntf, PackIntf, 
  58. {$ENDC}
  59.         TransSkel;
  60.  
  61.     procedure SetDWindow (theWind: WindowPtr);
  62.     procedure DisplayString (theStr: str255);
  63.     procedure DisplayHexLong (l: longint);
  64.     procedure DisplayHexInt (i: integer);
  65.     procedure DisplayHexChar (c: char);
  66.     procedure DisplayBoolean (b: Boolean);
  67.     procedure DisplayChar (c: char);
  68.     procedure DisplayInt (i: integer);
  69.     procedure DisplayLong (l: longint);
  70.     procedure DisplayLn;
  71.     procedure DisplayText (theText: Ptr; len: longint);
  72.     function GetNewDWindow (resourceNum: integer; behind: WindowPtr): WindowPtr;
  73.     function NewDWindow (bounds: Rect; title: Str255; visible: Boolean; behind: WindowPtr; goAway: Boolean; refcon: longint): WindowPTr;
  74.     procedure FlushDWindow (theWind: WindowPtr; byteCount: longint);
  75.     procedure GetDWindow (var theWind: WindowPtr);
  76.     procedure SetDWindowFlush (theWind: WindowPtr; maxText, flushAmt: longint);
  77.     procedure SetDWindowNotify (theWind: WindowPTr; p: ProcPtr);
  78.     procedure SetDWindowPos (theWind: WindowPtr; lineNum: integer);
  79.     procedure SetDWindowStyle (theWind: WindowPtr; font, size, wrap, just: integer);
  80.     function GetDWindowTE (theWind: WindowPtr): TEHandle;
  81.     function IsDWindow (theWind: WindowPtr): Boolean;
  82.     procedure TransDisplayInit;
  83.  
  84. implementation
  85.  
  86. {    Display window types, constants, variables.}
  87.  
  88.     const
  89.         monaco = 4;
  90.  
  91. {$IFC not singleDisplay }
  92.     type
  93.         DIPtr = ^DisplayInfo;
  94.         DIHandle = ^DIPtr;
  95.         DisplayInfo = record
  96.                 dWind: WindowPtr;        { display window         }
  97.                 dTE: TEHandle;            { window text            }
  98.                 dScroll: ControlHandle;    { window scroll bar      }
  99.                 dActivate: ProcPtr;        { notification procedure }
  100.                 dMaxText: longint;        { max text length        }
  101.                 dFlushAmt: longint;        { amount to autoflush    }
  102.                 dNext: DIHandle;            { next window structure  }
  103.             end;
  104. {$ENDC}
  105.  
  106.     var
  107.  
  108. { Look at TransDisplayInit procedure for initial values of these variables    }
  109.  
  110.         d_font, d_size: integer;                    { default font              }
  111.                                                 { default pointsize         }
  112.         d_wrap, d_just: integer;                { default word wrap (on)    }
  113.                                                 { default justification     }
  114.         d_maxText, d_flushAmt: longint;        { default max text allowed  }
  115.                                                 { default autoflush amount  }
  116.         d_activate: ProcPtr;                    { default notification proc }
  117.  
  118. {    Lowest allowable values for autoflush characteristics}
  119.  
  120.  
  121.         d_loMaxText, d_loFlushAmt: longint;
  122.  
  123. {$IFC not singleDisplay }
  124.  
  125.         dwList: DIHandle;
  126.  
  127. {    Variables pertaining to the display window being operated on}
  128. {    (updated, resized, etc.).  This window is not necessarily the}
  129. {    same as curDispWind!  These variables are synced to the window}
  130. {    with SyncGlobals. }
  131.  
  132.         dispInfo: DIHandle;        { info structure         }
  133. {$ENDC}
  134.  
  135.         dispWind: WindowPtr;            { the window             }
  136.         dispTE: TEHandle;                { window text            }
  137.         dispScroll: ControlHandle;        { the scroll bar         }
  138.         dActivate: ProcPtr;                { notification procedure }
  139.         dMaxText, dFlushAmt: longint;        { max text allowed       }
  140.         { amount to flush        }
  141.  
  142. {    curDispWind is the current output window.}
  143. {    If curDispWind = nil, output is turned off.}
  144.  
  145.         curDispWind: WindowPtr;
  146.  
  147. { -------------------------------------------------------------------- }
  148. {                Miscellaneous Internal (private) Routines                }
  149. { -------------------------------------------------------------------- }
  150.  
  151.  
  152.  
  153. {    Draw grow box of dispWind in lower right hand corner}
  154.  
  155.     procedure DrawGrowBox;
  156.  
  157.         var
  158.             oldClip: RgnHandle;
  159.             r: Rect;
  160.  
  161.     begin
  162.         r := dispWind^.portRect;
  163.         r.left := r.right - 15;        { draw only in corner }
  164.         r.top := r.bottom - 15;
  165.         oldClip := NewRgn;
  166.         GetClip(oldClip);
  167.         ClipRect(r);
  168.         DrawGrowIcon(dispWind);
  169.         SetClip(oldClip);
  170.         DisposeRgn(oldClip);
  171.     end;
  172.  
  173.  
  174.  
  175.  
  176. { -------------------------------------------------------------------- }
  177. {            Lowest-level Internal (Private) Display Window Routines        }
  178. { -------------------------------------------------------------------- }
  179.  
  180. {$IFC not singleDisplay}
  181.  
  182. {    Get display window info associated with window.}
  183. {    Return nil if window isn't a known display window.}
  184.  
  185.     function GetDInfo (theWind: WindowPtr): DIHandle;
  186.         var
  187.             h: DIHandle;
  188.             foundit: Boolean;
  189.     begin
  190.         h := dwList;
  191.         foundit := false;
  192.         while (h <> nil) and not foundit do
  193.             begin
  194.                 if h^^.dWind = theWind then
  195.                     begin
  196.                         GetDInfo := h;
  197.                         h := nil;
  198.                         foundit := true;
  199.                     end
  200.                 else
  201.                     h := h^^.dNext;
  202.             end;
  203.         if not foundit then
  204.             GetDInfo := nil;                    {make it a nop    }
  205.     end;
  206. {$ENDC}
  207.  
  208. {$IFC singleDisplay}
  209.  
  210.     procedure SyncGlobals (theWind: WindowPtr);
  211.     begin
  212.     end;            { make it a nop }
  213.  
  214. {$ELSEC }
  215. {    Synchronize globals to a display window.  theWind must be a legal}
  216. {    display window, with one exception:  if theWind is nil, the}
  217. {    variables are synced to the current port.  That is safe (and}
  218. {    correct) because:}
  219. {    (i)     nil is only passed by display window handler procedures,}
  220. {         which are only called by TransSkel for display window}
  221. {         events.}
  222. {    (ii) TransSkel always sets the port to the window before}
  223. {         calling the handler proc. <- NO LONGER TRUE!}
  224. {    Hence, use of the current port under these circumstances}
  225. {    always produces a legal display window.}
  226.  
  227. {    SyncGlobals is not used in single display mode, because the}
  228. {    globals are all set by SetupDWindow and do not change thereafter.}
  229.  
  230.     procedure SyncGlobals (theWind: WindowPtr);
  231.  
  232.         var
  233.             dp: DIPtr;
  234.     begin
  235.         if theWind = nil then                    { use current window }
  236.             GetPort(theWind);
  237.         dispWind := theWind;
  238.         dispInfo := GetDInfo(dispWind);
  239. {Bugfix by Ingemar 941208: The current port might not be a display window!}
  240.         if dispInfo <> nil then
  241.             begin
  242.                 dp := dispInfo^;
  243.                 dispScroll := dp^.dScroll;
  244.                 dispTE := dp^.dTE;
  245.                 dActivate := dp^.dActivate;
  246.                 dMaxText := dp^.dMaxText;
  247.                 dFlushAmt := dp^.dFlushAmt;
  248.             end;
  249.     end;
  250. {$ENDC}
  251.  
  252. {    Calculate the dimensions of the editing rectangle for}
  253. {    dispWind (which must be set properly and is assumed to }
  254. {    the current port).  (The viewRect and destRect are the}
  255. {    same size .) Assumes the port , text font and text size are all}
  256. {    set properly.  The viewRect is sized so that an integral}
  257. {    number of lines can be displayed in it, i.e., so that a}
  258. {    partial line never shows at the bottom. }
  259.  
  260.     procedure CalcEditRect (var r: Rect);
  261.  
  262.         var
  263.             f: FontInfo;
  264.             lineHeight: integer;
  265.  
  266.     begin
  267.         GetFontInfo(f);
  268.         lineHeight := f.ascent + f.descent + f.leading;
  269.         r := dispWind^.portRect;
  270.         r.left := r.left + 4;
  271.         r.right := r.right - 17;            { leave room for scroll bar + 2 }
  272.         r.top := r.top + 2;
  273.         r.bottom := r.top + ((r.bottom - (r.top - 2)) div lineHeight) * lineHeight;
  274.     end;
  275.  
  276. {    Calculate the dimensions of the scroll bar rectangle for the}
  277. {    window.  Make sure that the edges overlap the window frame and}
  278. {    the grow box.}
  279.  
  280.     procedure CalcScrollRect (var r: Rect);
  281.  
  282.     begin
  283.         r := dispWind^.portRect;
  284.         r.right := r.right + 1;
  285.         r.left := r.right - 16;
  286.         r.top := r.top - 1;
  287.         r.bottom := r.bottom - 14;
  288.     end;
  289.  
  290. {    Calculate the number of lines currently scrolled off}
  291. {    the top.}
  292.  
  293.     function LinesOffTop: integer;
  294.  
  295.         var
  296.             ePtr: TEPtr;
  297.  
  298.     begin
  299.         ePtr := dispTE^;
  300.         LinesOffTop := (ePtr^.viewRect.top - ePtr^.destRect.top) div ePtr^.lineHeight;
  301.     end;
  302.  
  303. {    Highlight the scroll bar properly.  This means that it's not}
  304. {    made active if the window itself isn't active, even if}
  305. {    there's enough text to fill the window. }
  306.  
  307.     procedure HiliteScroll;
  308.         var
  309.             result: integer;
  310.     begin
  311.         if (GetCtlMax(dispScroll) > 0) and (dispWind = FrontWindow) then
  312.             result := 0
  313.         else
  314.             result := 255;
  315.         HiliteControl(dispScroll, result);
  316.     end;
  317.  
  318. {    Scroll to the correct position.  lDelta is the}
  319. {    amount to CHANGE the current scroll setting by.}
  320. {    Positive scrolls the text up, negative down.}
  321.  
  322.     procedure ScrollText (lDelta: integer);
  323.  
  324.         var
  325.             lHeight, newLine, topLine: integer;
  326.  
  327.     begin
  328.         lHeight := dispTE^^.lineHeight;
  329.         topLine := LinesOffTop;
  330.         newLine := topLine + lDelta;
  331.         if newLine < 0 then
  332.             newLine := 0;
  333.         if newLine > GetCtlmax(dispScroll) then
  334.             newLine := GetCtlMax(dispScroll);
  335.         SetCtlValue(dispScroll, newLine);
  336.         TEScroll(0, (topLine - newLine) * lHeight, dispTE);
  337.     end;
  338.  
  339.  
  340. {    Filter proc for tracking mousedown in scroll bar . The code}
  341. {    for the part originally hit is stored in the control 's reference}
  342. {    value by Mouse ( ) before calling this . }
  343.  
  344.  
  345. {    Scroll by one line if the mouse is in an arrow.  Scroll by a half}
  346. {    window's worth of lines if the mouse is in a page region. }
  347.  
  348.     procedure TrackScroll (theScroll: ControlHandle; partCode: integer);
  349.  
  350.         var
  351.             lDelta, halfPage: integer;
  352.  
  353.     begin
  354.         if partCode = GetCRefCon(theScroll) then        { still in same part? }
  355.             begin
  356.                 halfPage := ((dispTE^^.viewRect.bottom - dispTE^^.viewRect.top) div dispTE^^.lineHeight) div 2;
  357.                 if halfPage = 0 then
  358.                     halfPage := halfPage + 1;
  359.                 case partCode of
  360.                     inUpButton: 
  361.                         lDelta := -1;
  362.                     inDownButton: 
  363.                         lDelta := 1;
  364.                     inPageUp: 
  365.                         lDelta := -halfPage;
  366.                     inPageDown: 
  367.                         lDelta := halfPage;
  368.                     otherwise
  369.                 end;
  370.                 ScrollText(lDelta);
  371.             end;
  372.     end;
  373.  
  374. {    Adjust the text in the text record and the scroll bar.  This is}
  375. {    called for major catastrophes, such as resizing the window, or}
  376. {    changing the word wrap style.  It makes sure the view and}
  377. {    destination rectangles are sized properly, and that the bottom}
  378. {    line of text never scrolls up past the bottom line of the}
  379. {    window, if there's enough to fill the window, and that the}
  380. {    scroll bar max and current values are set properly.}
  381.  
  382. {    Resizing the dest rect just means resetting the right edge}
  383. {    (the top is NOT reset), since text might be scrolled off the}
  384. {    top (i.e., destRect.top != 0).}
  385.  
  386.     procedure OverhaulDisplay;
  387.  
  388.         var
  389.             r: Rect;
  390.             nLines, visLines, topLines, scrollLines, lHeight: integer;
  391.             { number of lines in TERec }
  392.         { number of lines displayable in window }
  393.         { number of lines currently scrolled off top }
  394.         { number of lines to scroll down }
  395.  
  396.     begin
  397.         CalcEditRect(r);
  398.         dispTE^^.destRect.right := r.right;
  399.         dispTE^^.viewRect := r;
  400.         TECalText(dispTE);        { recalc line starts }
  401.         lHeight := dispTE^^.lineHeight;
  402.         nLines := dispTE^^.nLines;
  403.         visLines := (r.bottom - r.top) div lheight;
  404.         topLines := LinesoffTop;
  405.  
  406. {    If the text doesn't fill the window (visLines > nLines - topLines),}
  407. {    pull the text down if possible (if topLines > 0).  Make sure}
  408. {    not to try to scroll down by more lines than are hidden off the top .}
  409.  
  410.         scrollLines := visLines - (nLines - topLines);
  411.         if (scrollLines > 0) and (topLines > 0) then
  412.             begin
  413.                 if scrollLines > topLines then
  414.                     scrollLines := topLines;
  415.                 TEScroll(0, scrollLInes * lHeight, dispTE);
  416.                 toplines := topLines - scrollLines;
  417.             end;
  418.         TEUpdate(r, dispTE);
  419.         if nLines - visLines < 0 then
  420.             SetCtlMax(dispScroll, 0)
  421.         else
  422.             SetCtlMax(dispScroll, nLines - VisLines);
  423.         SetCtlValue(dispScroll, topLines);
  424.         HiliteScroll;
  425.     end;
  426.  
  427.     procedure callpnoarg (myProc: ProcPtr);
  428.  
  429. { For all the Procedures that are called with no arguments                            }
  430.  
  431.     inline
  432.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  433.         $4e90;
  434.  
  435.     procedure callpBoolean (myBool: Boolean; myProc: ProcPtr);
  436.  
  437. { Two calls use Booleans as one parameter arguments.  This procedure handles    }
  438. { both of them.                                                                            }
  439.  
  440.     inline
  441.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  442.         $4e90;
  443.  
  444. { ---------------------------------------------------------------- }
  445. {                        Window Handler Routines                        }
  446. { ---------------------------------------------------------------- }
  447.  
  448.  
  449.  
  450. {    When the window comes active, highlight the scroll bar appropriately.}
  451. {    When the window is deactivated, un-highlight the scroll bar.}
  452. {    Redraw the grow box.}
  453.  
  454. {    Notify the host as appropriate.}
  455.  
  456. {    Note that clicking close box hides the window, which generates a}
  457. {    deactivate event, so there is no need for a close notifier.}
  458.  
  459.  
  460.     procedure Activate (isActive: Boolean);
  461.  
  462.     begin
  463.         SyncGlobals(nil);                { sync to current port }
  464.         DrawGrowBox;
  465.         HiliteScroll;
  466.  
  467.         if dActivate <> nil then
  468.             callpBoolean(isActive, dActivate);
  469.     end;
  470.  
  471. {    Update window.  The update event might be in response to a}
  472. {    window resizing.  If so, move and resize the scroll bar,}
  473. {    and recalculate the text display.}
  474.  
  475. {    The ValidRect call is done because the HideControl adds the}
  476. {    control bounds box to the update region - which would generate}
  477. {    another update event!  Since everything is redrawn below anyway,}
  478. {    the ValidRect is used to cancel the update.}
  479.  
  480.     procedure Update (resized: Boolean);
  481.  
  482.         var
  483.             r: Rect;
  484.  
  485.     begin
  486.         SyncGlobals(nil);                    { sync to current port }
  487.         r := dispWind^.portRect;
  488.         EraseRect(r);
  489.         if resized then
  490.             begin
  491.                 HideControl(dispScroll);
  492.                 r := dispScroll^^.contrlRect;
  493.                 ValidRect(r);
  494.                 CalcScrollRect(r);
  495.                 SizeControl(dispScroll, 16, r.bottom - r.top);
  496.                 MoveControl(dispScroll, r.left, r.top);
  497.                 OverHaulDisplay;
  498.                 ShowControl(dispScroll);
  499.             end
  500.         else
  501.             begin
  502.                 r := dispTE^^.viewRect;
  503.                 TEUpdate(r, dispTE);
  504.             end;
  505.         DrawGrowBox;
  506.         DrawControls(dispWind);    { redraw scroll bar }
  507.     end;
  508.  
  509. {    Handle mouse clicks in window}
  510.  
  511.     procedure Mouse (thePt: Point; t: longint; mods: integer);
  512.  
  513.         var
  514.             thePart: integer;
  515.             oldCtlValue: integer;
  516.     begin
  517.         SyncGlobals(nil);                    { Sync to current port    }
  518.  
  519.         thePart := TestControl(dispScroll, thePt);
  520.         if thePart = inThumb then
  521.             begin
  522.                 OldCtlValue := GetCtlValue(dispScroll);
  523.                 if TrackControl(dispScroll, thePt, nil) = inThumb then
  524.                     ScrollText(GetCtlValue(dispScroll) - oldCtlValue);
  525.             end
  526.         else if thePart <> 0 then
  527.             begin
  528.                 SetCRefCon(dispScroll, longint(thePart));
  529.                 oldCtlValue := TrackControl(dispScroll, thePt, @TrackScroll);
  530.             end;
  531.     end;
  532.  
  533. {    Remove the display window from the list, and dispose of it.}
  534. {    Since the clobber procedure is never called except for real display}
  535. {    windows, and since the list must therefore be non-empty, it is}
  536. {    not necessary to check the legality of the window or that the}
  537. {    window's in the list.}
  538.  
  539. {    Must do SetDWindow (nil) to turn output off, if the window being}
  540. {    clobbered is the current output window.}
  541.  
  542.     procedure Clobber;
  543.  
  544.         var
  545. {$IFC not singleDisplay}
  546.             h, h2: DIHandle;
  547. {$ENDC}
  548.             keepgoing: Boolean;
  549.  
  550.     begin
  551.         SyncGlobals(nil);                    { sync to current port }
  552.         if dispWind = curDispWind then    { is it the first window in list? }
  553.             SetDWindow(nil);
  554. {$IFC not singleDisplay}
  555.         if dwList^^.dWind = dispWind then    { found it }
  556.             begin
  557.                 h2 := dwList;
  558.                 dwList := dwList^^.dNext;
  559.             end
  560.         else
  561.             begin
  562.                 h := dwList;
  563.                 keepgoing := true;
  564.                 while (h <> nil) and keepgoing do
  565.                     begin
  566.                         h2 := h^^.dNext;
  567.                         if h2^^.dWind = dispWind then
  568.                             begin
  569.                                 h^^.dNext := h2^^.dNext;
  570.                                 keepgoing := false;
  571.                             end;
  572.                         h := h2;
  573.                     end;
  574.             end;
  575.         DisposHandle(Handle(h2));        { get rid of information structure }
  576. {$ENDC}
  577.         TEDispose(dispTE);                { toss text record }
  578.         DisposeWindow(dispWind);        { toss window and scroll bar }
  579.         dispWind := nil;
  580.     end;
  581.  
  582. { ---------------------------------------------------------------- }
  583. {                            Control Routines                        }
  584. { ---------------------------------------------------------------- }
  585.  
  586.  
  587. {    Test whether a window is a legal display window or not }
  588.  
  589.     function IsDWindow;
  590.  
  591.     begin
  592. {$IFC singleDisplay}
  593.         IsDWindow := (theWind = dispWind) and (dispWind <> nil);
  594. {$ELSEC}
  595.         IsDWindow := GetDInfo(theWind) <> nil;
  596. {$ENDC}
  597.     end;
  598.  
  599. {    Return handle to display window's text record}
  600.  
  601.     function GetDWindowTE;
  602.  
  603. {$IFC not singleDisplay}
  604.  
  605.         var
  606.             dInfo: DIHandle;
  607. {$ENDC}
  608.  
  609.     begin
  610. {$IFC not singleDisplay}
  611.  
  612. {Fix by Ingemar -94: The following line was missing in the 2.0 release:}
  613.         dInfo := GetDInfo(theWind);
  614.  
  615.         if dInfo = nil then {GetDInfo(theWind)}
  616.             GetDWindowTE := nil
  617.         else
  618.             GetDWIndowTE := dInfo^^.dTE;
  619. {$ELSEC}
  620.         if ISDWindow(theWind) then
  621.             GetDWindowTE := dispTE
  622.         else
  623.             GetDWindowTE := nil;
  624. {$ENDC}
  625.     end;
  626.  
  627. {    Change the text display characteristics of a display window}
  628. {    and redisplay it.  As a side effect, this always scrolls to the}
  629. {    home position.}
  630.  
  631.     procedure SetDWindowStyle;
  632.  
  633.         var
  634.             savePort: GrafPtr;
  635.             f: FontInfo;
  636.             te: TEHandle;
  637.             r: Rect;
  638.  
  639.     begin
  640.         if theWind = nil then            { reset window creation defaults }
  641.             begin
  642.                 d_font := font;
  643.                 d_size := size;
  644.                 d_wrap := wrap;
  645.                 d_just := just;
  646.             end
  647.         else
  648.             begin
  649.                 if IsDWindow(theWind) then
  650.                     begin
  651.                         GetPort(savePort);
  652.                         SyncGlobals(theWind);
  653.                         SetPort(dispWind);
  654.                         te := dispTE;
  655.                         r := te^^.viewRect;
  656.                         EraseRect(r);
  657.                         r := te^^.destRect;    { scroll home without redrawing }
  658.  
  659.                         OffsetRect(r, 0, 2 - r.top);
  660.                         te^^.destRect := r;
  661.                         te^^.crOnly := wrap;    { set word wrap }
  662.                         TESetJust(just, te);    { set justification }
  663.                         TextFont(font);         { set the font and point size }
  664.                         TextSize(size);        { of text record (this is the }
  665.                         GetFontInfo(f);        { hard part) }
  666.                         te^^.lineHeight := f.ascent + f.descent + f.leading;
  667.                         te^^.fontAscent := f.ascent;
  668.                         te^^.txFont := font;
  669.                         te^^.txSize := size;
  670.  
  671.                         OverhaulDisplay;
  672.                         SetPort(savePort);
  673.                     end;
  674.             end;
  675.     end;
  676.  
  677. {    Scroll the text in the window so that line lineNum is at the top.}
  678. {    First line is line zero.}
  679.  
  680.     procedure SetDWindowPos;
  681.  
  682.         var
  683.             savePort: GrafPtr;
  684.  
  685.     begin
  686.         if IsDWindow(theWind) then
  687.             begin
  688.                 GetPort(savePort);
  689.                 SyncGlobals(theWind);
  690.                 SetPort(dispWind);
  691.                 ScrollText(lineNum - GetCtlValue(dispScroll));
  692.                 SetPort(savePort);
  693.             end;
  694.     end;
  695.  
  696. {    Set display window activate notification procedure.}
  697. {    Pass nil to disable it.}
  698.  
  699.     procedure SetDWindowNotify;
  700. {$IFC not singleDisplay}
  701.         var
  702.             dInfo: DIHAndle;
  703. {$ENDC}
  704.  
  705.     begin
  706.         if theWind = nil then            { reset window creation default }
  707.             d_activate := p
  708.         else
  709.             begin
  710. {$IFC singleDisplay}
  711.                 if (ISDWindow(theWind)) then
  712.                     dActivate := p;
  713. {$ELSEC}
  714.                 dInfo := GetDInfo(theWind);
  715.                 if dInfo <> nil then
  716.                     dInfo^^.dActivate := p;
  717. {$ENDC}
  718.             end;
  719.     end;
  720.  
  721. {    Set display window autoflush characteristics}
  722.  
  723.     procedure SetDWindowFlush;
  724.  
  725. {$IFC not singleDisplay}
  726.         var
  727.             dInfo: DIHandle;
  728. {$ENDC}
  729.  
  730.     begin
  731.         if maxText > longint(32767) then
  732.             maxText := 32767;
  733.         if maxText < d_loMaxText then
  734.             maxText := d_loMaxText;
  735.         if flushAmt < d_loFlushAmt then
  736.             flushAmt := d_loFlushAmt;
  737.         if theWind = nil then
  738.             begin            { reset window creation defaults }
  739.                 d_maxText := maxText;
  740.                 d_flushAmt := flushAmt;
  741.             end
  742.         else
  743.             begin
  744. {$IFC singleDisplay}
  745.                 if (IsDWindow(theWind)) then
  746.                     begin
  747.                         dMaxText := maxText;
  748.                         dFlushAmt := flushAmt;
  749.                     end;
  750. {$ELSEC}
  751.                 dInfo := GetDInfo(theWind);
  752.                 if dInfo <> nil then
  753.                     begin
  754.                         dInfo^^.dMaxText := maxText;
  755.                         dInfo^^.dFlushAmt := flushAmt;
  756.                     end;
  757. {$ENDC}
  758.             end;
  759.     end;
  760.  
  761. {    Set which display window is to be used for output.  If theWind}
  762. {    is nil, output is turned off.  If theWind is not a legal display}
  763. {    window, nothing is done.}
  764.  
  765.     procedure SetDWindow;
  766.  
  767.     begin
  768.         if (theWind = nil) or IsDWindow(theWind) then
  769.             curDispWind := theWind;
  770.     end;
  771.  
  772. {    Get the WindowPtr of the current output display window.  If}
  773. {    output is turned off, this will be nil.}
  774.  
  775.     procedure GetDWindow;
  776.  
  777.     begin
  778.         theWind := curDispWind;
  779.     end;
  780.  
  781. {    Flush text from the window and readjust the display.}
  782.  
  783.     procedure FlushDWindow;
  784.  
  785.     begin
  786.         if IsDWindow(theWind) then
  787.             begin
  788.                 SyncGlobals(theWind);
  789.                 TESetSelect(longint(0), byteCount, dispTE);    { select text }
  790.                 TEDelete(dispTE);                                { clobber it }
  791.                 OverhaulDisplay;
  792.             end;
  793.     end;
  794.  
  795. {    Create and initialize a display window and the associated data}
  796. {    structures, and return the window pointer.  Install window in}
  797. {    list of display windows.}
  798.  
  799.     procedure SetupDWindow;
  800.  
  801.         var
  802.             r: Rect;
  803.             savePort: GrafPtr;
  804. {$IFC not singleDisplay}
  805.             dInfo: DIHandle;
  806. {$ENDC}
  807.             dummy: Boolean;
  808.  
  809.     begin
  810.         dummy := SkelWindow(dispWind, @Mouse, nil, @Update, @Activate, nil, @Clobber, nil, false);
  811.     { the window }
  812.         { mouse click handler }
  813.         { key clicks are ignored }
  814.         { window updating procedure }
  815.         { window activate/deactivate procedure }
  816.         { TransSkel hides window if no close proc }
  817.         { (generates deactivate event) }
  818.         { window disposal procedure }
  819.         { no idle proc }
  820.         { irrelevant since no idle proc }
  821.  
  822. {    Build the scroll bar.  Make sure the borders overlap the}
  823. {    window frame and the frame of the grow box.}
  824.  
  825.         CalcScrollRect(r);
  826.         dispScroll := NewControl(dispWind, r, '', true, 0, 0, 0, scrollBarProc, longint(0));
  827.  
  828. {    Create the TE record used for text display.  Use defaults for}
  829. {    display characteristics.  Setting window style overhauls}
  830. {    display, so can cancel and update event pending for the window.}
  831.  
  832.         CalcEditRect(r);
  833.         dispTE := TENew(r, r);
  834.  
  835. {$IFC not singleDisplay}
  836. {    Get new information structure, attach to list of known display}
  837. {    windows.}
  838.  
  839.         dInfo := DIHandle(NewHandle(sizeof(DisplayInfo)));
  840.  
  841.         dInfo^^.dNext := dwList;
  842.         dwList := dInfo;
  843.         dInfo^^.dWind := dispWind;
  844.         dInfo^^.dScroll := dispScroll;
  845.         dInfo^^.dTE := dispTE;
  846. {$ENDC}
  847.  
  848.         SetDWindowNotify(dispWind, d_activate);
  849.         SetDWindowFlush(dispWind, d_maxtext, d_flushAmt);
  850.         SetDWindowStyle(dispWind, d_font, d_size, d_wrap, d_just);
  851.  
  852. {    Make window current display output window}
  853.  
  854.         SetDWindow(dispWind);
  855.     end;
  856.  
  857. {    Create and initialize a display window and the associated data}
  858. {    structures, and return the window pointer.  Install window in}
  859. {    list of display windows.  In single-window mode, disallow}
  860. {    creation of a new window if one already exists.}
  861.  
  862. {    The parameters are similar to those for NewWindow.  See Inside}
  863. {    Macintosh.}
  864.  
  865.     function NewDWindow;
  866.  
  867.     begin
  868. {$IFC singleDisplay}
  869.         if dispWind <> nil then
  870.             NewDWindow := nil
  871.         else
  872. {$ENDC}
  873.             begin
  874.                 dispWind := NewWindow(nil, bounds, title, visible, documentProc, behind, goAway, refCon);
  875.                 SetUpDWindow;
  876.                 NewDWindow := dispWind;
  877.             end;
  878.     end;
  879.  
  880. {    Create and initialize a display window (using a resource) and}
  881. {    the associated data structures, and return the window pointer.}
  882. {    Install window in list of display windows.  In single-window}
  883. {    mode, disallow creation of a new window if one already exists.}
  884.  
  885. {    The parameters are similar to those for GetNewWindow.  See Inside}
  886. {    Macintosh.}
  887.  
  888.     function GetNewDWindow;
  889.  
  890.     begin
  891. {$IFC singleDisplay}
  892.         if dispWind <> nil then
  893.             GetNewDWindow := nil
  894.         else
  895. {$ENDC}
  896.             begin
  897.                 dispWind := GetNewWindow(resourceNum, nil, behind);
  898.                 SetUPDWindow;
  899.                 GetNewDWindow := dispWind;
  900.             end;
  901.     end;
  902.  
  903. { ------------------------------------------------------------ }
  904. {                        Output Routines                            }
  905. { ------------------------------------------------------------ }
  906.  
  907.  
  908. {}
  909. {    Write text to display area if output is on (curDispWind != nil).}
  910. {    DisplayText is the fundamental output routine.  All other}
  911. {    output calls map (eventually) to it.}
  912.  
  913. {    First check whether the insertion will cause overflow and flush}
  914. {    out some stuff if so.  Insert new text at the end, then test}
  915. {    whether lines must be scrolled to get the new stuff to show up.}
  916. {    If yes, then do the scroll.  Set values of scroll bar properly}
  917. {    and highlight as appropriate.}
  918.  
  919. {    The current port is preserved.  Since all output calls end up}
  920. {    here, it's the only output routine that has to save the port}
  921. {    and check whether output is on.}
  922.  
  923.     procedure DisplayText;
  924.  
  925.         var
  926.             nLines, dispLines, topLines, scrollLines, lHeight: integer;
  927.         { number of lines in TERec }
  928.         { number of lines displayable in window }
  929.         { number of lines currently scrolled off top }
  930.         { number of lines to scroll up }
  931.             r: Rect;
  932.             savePort: GrafPtr;
  933.             dTE: TEHandle;
  934.  
  935.     begin
  936.         if curDispWind <> nil then
  937.             begin
  938.                 GetPort(savePort);
  939.                 SetPort(curDispWind);
  940.                 SyncGlobals(curDispWind);
  941.                 dTE := dispTE;
  942.  
  943.                 if dTE^^.teLength + len > dMaxText then    { check overflow }
  944.                     begin
  945.                         FlushDWindow(dispWind, dFlushAmt);
  946.                         DisplayString('(autoflush occurred)');
  947.                     end;
  948.                 lHeight := dTE^^.lineHeight;
  949.                 TESetSelect(longint(32767), longint(32767), dTE);
  950.                 TEInsert(theText, len, dTE);
  951.                 r := dTE^^.viewRect;
  952.                 nLines := dTE^^.nLines;
  953.                 dispLines := (r.bottom - r.top) div lHeight;
  954.                 topLines := LinesOffTop;
  955.                 scrollLines := nLines - (topLines + dispLines);
  956.                 if scrollLines > 0 then                                 { must scroll up }
  957.                     TEScroll(0, -lHeight * scrollLines, dTE);            { scroll up }
  958.                 topLines := nLines - dispLines;
  959.                 if (topLines >= 0) and (GetCtlMax(dispScroll) <> topLines) then
  960.                     begin
  961.                         SetCtlMax(dispScroll, topLines);
  962.                         SetCtlValue(dispScroll, topLines);
  963.                     end;
  964.                 HiliteScroll;
  965.                 SetPort(savePort);
  966.             end;
  967.     end;
  968.  
  969. {    Derived output routines:}
  970.  
  971. {    DisplayString    Write (Pascal) string}
  972.  
  973. {    DisplayLong        Write value of long integer}
  974. {    DisplayInt        Write value of integer}
  975. {    DisplayChar        Write character}
  976.  
  977. {    DisplayHexLong    Write value of long integer in hex (8 digits)}
  978. {    DisplayHexInt    Write value of integer in hex (4 digits)}
  979. {    DisplayHexChar    Write value of character in hex (2 digit)}
  980.  
  981. {    DisplayBoolean    Write boolean value}
  982. {    DisplayLn        Write carriage return}
  983.  
  984.     procedure DisplayString;
  985.  
  986.         var
  987.             myPtr: Ptr;
  988.  
  989.     begin
  990.         myPtr := Ptr(longint(@theStr) + 1);
  991.         DisplayText(myPtr, longint(length(theSTr)));
  992.     end;
  993.  
  994.     procedure DisplayLong;
  995.  
  996.         var
  997.             s: Str255;
  998.  
  999.     begin
  1000.         NumToString(l, s);
  1001.         DisplayString(s);
  1002.     end;
  1003.  
  1004.     procedure DisplayInt;
  1005.  
  1006.     begin
  1007.         DisplayLong(longint(i));
  1008.     end;
  1009.  
  1010.     procedure DisplayChar;
  1011.  
  1012.         var
  1013.             myPtr: Ptr;
  1014.  
  1015.     begin
  1016.         myPtr := @c;
  1017.         myPtr := Ptr(longint(myPtr) + 1);
  1018.         DisplayText(myPtr, longint(1));
  1019.     end;
  1020.  
  1021.     procedure DisplayLn;
  1022.  
  1023.     begin
  1024.         DisplayChar(char(13));
  1025.     end;
  1026.  
  1027.     procedure DisplayBoolean;
  1028.  
  1029.     begin
  1030.         if b then
  1031.             DisplayString('True')
  1032.         else
  1033.             DisplayString('False');
  1034.     end;
  1035.  
  1036.     procedure HexByte (value: integer);    {value should be 0..15}
  1037.     begin
  1038.         if value < 10 then
  1039.             DisplayChar(char(value + integer('0')))
  1040.         else
  1041.             DisplayChar(char(value + (integer('a') - 10)));
  1042.     end;
  1043.  
  1044.     procedure DisplayHexChar;
  1045.  
  1046.     begin
  1047.         HexByte(integer(BitAnd(BitShift(longint(c), -4), $0000000f)));
  1048.         HexByte(integer(BitAnd(longint(c), $0000000f)));
  1049.     end;
  1050.  
  1051.     procedure DisplayHexInt;
  1052.  
  1053.     begin
  1054.         DisplayHexChar(char(BitAnd(BitShift(longint(i), -8), $000000ff)));
  1055.         DisplayHexChar(char(BitAnd(longint(i), $000000ff)));
  1056.     end;
  1057.  
  1058.     procedure DisplayHexLong;
  1059.  
  1060.     begin
  1061.         DisplayHexInt(Integer(BitAnd(BitShift(l, -16), $0000ffff)));
  1062.         DisplayHexInt(integer(LoWord(l)));
  1063.     end;
  1064.  
  1065.     procedure TransDisplayInit;
  1066.  
  1067.     begin
  1068.  
  1069. {    Default values for display window characteristics}
  1070.  
  1071.         d_font := monaco;        { default font              }
  1072.         d_size := 9;                { default pointsize         }
  1073.         d_wrap := 0;                { default word wrap (on)    }
  1074.         d_just := teJustLeft;    { default justification     }
  1075.         d_maxText := 30000;    { default max text allowed  }
  1076.         d_flushAmt := 25000;    { default autoflush amount  }
  1077.         d_activate := nil;        { default notification proc }
  1078.  
  1079. {    Lowest allowable values for autoflush characteristics}
  1080.  
  1081.         d_loMaxText := 100;
  1082.         d_loFlushAmt := 100;
  1083.  
  1084. {    dwList points to a list of structures describing the known display}
  1085. {    windows.}
  1086.  
  1087. {    curDispWind is the current output window.}
  1088. {    If curDispWind = nil, output is currently turned off.}
  1089.  
  1090. {$IFC not singleDisplay}
  1091.         dwList := nil;
  1092. {$ENDC}
  1093.         dispWind := nil;
  1094.         curDispWind := nil;
  1095.     end;
  1096. end.